/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package pt.mleiria.supervisedlearning;

import pt.mleiria.utils.EnvSettings;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import pt.mleiria.datastructures.functions.Heaviside;
import pt.mleiria.datastructures.interfaces.OneVarFunction;
import pt.mleiria.datastructures.iterations.IteratorProcessor;
import static pt.mleiria.supervisedlearning.KNearestNeighbour.LOG;
import pt.mleiria.utils.IOUtils;
import pt.mleiria.utils.LogUtils;

/**
 * Input and Hidden layers have an extra unit for thresholding
 *
 * @author manuel
 */
public class Perceptron extends IteratorProcessor {

    private final static Logger LOGGER = Logger.getLogger(Perceptron.class.getName());
    private int sensorDimension;
    private int sampleSize;
    /**
     * input sensors
     */
    private int[][] x;
    /**
     * weights connecting the input layer to the hidden layer 
     * w1ij -> i indexes the input layer 
     *      -> j indexes the hidden units
     */
    private double[][] w1;
    /**
     * weights connecting the hidden layer to the output layer 
     * w2ij -> i indexes the hidden layer 
     *      -> j indexes the output layer
     */
    private double[][] w2;
    /**
     * Desired output for input sensors
     */
    private int[][] d;
    /**
     * Actual output
     */
    private int[][] y;
    /**
     * alpha: learning rate
     */
    private double alpha;

    private final OneVarFunction f;

    public Perceptron() {
        f = new Heaviside(0.5);
    }

    @Override
    public void initializeIterations() {
        try {
            setMaximumIterations(50);
            setDesiredPrecision(0.1);
            x = IOUtils.loadFileTo2DArray(EnvSettings.NAND_INPUT, ",");
            d = IOUtils.loadFileTo2DArray(EnvSettings.NAND_OUTPUT, null);
            LOG.log(Level.INFO, "x:\n{0}", LogUtils.showArrayContents(x));
            LOG.log(Level.INFO, "d:\n{0}", LogUtils.showArrayContents(d));
            x = redimForThreshold(x);
            //initializeWeights();

        } catch (IllegalArgumentException e) {
            LOGGER.log(Level.SEVERE, "Error loading data file:[{0}", e.getMessage());
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "Error loading data file:[{0}", e.getMessage());
        }

    }
    /**
     * 
     */
    private int[][] redimForThreshold(int[][] arr){
        int rows = arr.length + 1;
        LOG.log(Level.INFO, "rows: {0}", rows);
        int[][] newComponents = new int[rows][arr[0].length];
        
        for(int i = 0; i < rows; i++){
            int[] row = arr[i];
            for(int j = 0; j < row.length; j++){
                if(i == 0){
                    newComponents[i][j] = 1;
                }else{
                    newComponents[i][j] = row[j];
                }
                
            }
        }
        LOG.log(Level.INFO, "newComponents:\n{0}", LogUtils.showArrayContents(newComponents));
        return newComponents;
    }
    /**
     * Initialize weights randomly between 0.1 and 0.9
     */
    private void initializeWeights(){
        w1 = new double[x.length][x.length-1];
        w2 = new double[x.length][x.length-1];
        byte i, j;
        for(i = 0; i < w1.length; i++){
            for(j = 0; j < w1[i].length; j++){
                w1[i][j] = 0.8 * Math.random() + 0.1;
            }
        }
        for(i = 0; i < w2.length; i++){
            for(j = 0; j < w2[i].length; j++){
                w2[i][j] = 0.8 * Math.random() + 0.1;
            }
        }
        LOG.log(Level.INFO, "w1:\n{0}", LogUtils.showArrayContents(w1));
        LOG.log(Level.INFO, "w2:\n{0}", LogUtils.showArrayContents(w2));
    }

    @Override
    public double evaluateIteration() {

        return 0.0;
    }

    private void updateWeights() {

    }

    public static void main(String[] args) {
        Perceptron p = new Perceptron();
        //p.initializeIterations();
        p.evaluate();
    }

}
